/*
 * File Name  :POHelper.java
 * Create Date:2012-11-5 上午10:58:51
 * Author     :woden
 */

package com.wodensoft.core.db;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 动态PO辅助类.
 * 
 */
public class POHelper {

    public static final String ENTRY_NAME_KEY = "$type$";

    /**
     * 创建空PO实例.
     * 
     * @param entryName
     * @return
     */
    public static PO newPO(String entryName) {
        PO po = new PO(entryName);
        return po;
    }
    
    public static PO newPO(String entryName, Map<String, Object> attributes) {
        PO po = new PO(entryName, attributes);
        return po;
    }

    /**
     * 动态PO代理.
     * 
     */
    public static final class PO {
        private Map<String, Object> po;

        public String getEntryName(){
            return getString(ENTRY_NAME_KEY);
        }
        
        public PO(String entryName) {
            this(entryName, new HashMap<String, Object>());
        }

        public PO(String entryName, Map<String, Object> po) {
            this.po = po;
            this.po.put(ENTRY_NAME_KEY, entryName);
        }

        public void set(String name, Object value) {
            po.put(name, value);
        }

        /**
         * 一对多关系仲的<code>Map</code>结构.
         * 
         * @param entryName
         * @param name
         * @param value
         */
        public void addSubEntry(String entryName, String index, Map<String, Object> value) {
            if (!po.containsKey(entryName)) {
                po.put(entryName, new HashMap<String, Map<String, Map<String, Object>>>());
            }
            Map<String, Map<String, Object>> subs = (Map<String, Map<String, Object>>)getSubEntrys(entryName);
            subs.put((String)value.get(index), value);
        }

        /**
         * 一对多关系<code>List</code>结构.
         * 
         * @param entryName
         * @param value
         */
        public void addSubItem(String entryName, Map<String, Object> value) {
            if (!po.containsKey(entryName)) {
                po.put(entryName, new ArrayList<Map<String, Object>>());
            }
            List<Map<String, Object>> subs = (List<Map<String, Object>>) getSubList(entryName);
            subs.add(value);
        }

        public Object get(String name) {
            return po.get(name);
        }

        public String getString(String name) {
            return (String) get(name);
        }

        public Long getLong(String name) {
            return (Long) get(name);
        }

        public Integer getIntger(String name) {
            return (Integer) get(name);
        }

        public Date getDate(String name) {
            return (Date) get(name);
        }

        public BigDecimal getMoney(String name) {
            return (BigDecimal) get(name);
        }

        @SuppressWarnings("unchecked")
        public Map<String, Map<String, Object>> getSubEntrys(String name) {
            return (Map<String, Map<String, Object>>) get(name);
        }

        @SuppressWarnings("unchecked")
        public List<Map<String, Object>> getSubList(String name) {
            return (List<Map<String, Object>>) get(name);
        }

        /**
         * 将动态PO包装类转换成MAP(直接放到dao层处理).
         * 
         * @return 动态对象<code>Map</code>.
         */
        public final Map<String, Object> toEntry() {
            return po;
        }
    }

    /**
     * 查询条件，生成queryMap.<br>
     * 
     * <pre>
     * +----------+---------------+-------------+--------------------------------------------------------------+
     * +   type   +   directions  +   command   +                          note                                +
     * +----------+---------------+-------------+--------------------------------------------------------------+
     * +          +               + sisn        + is null.1:null;0:not null.                                   +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + sn          + null.                                                        +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + snn         + not null.                                                    +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + sl          + like." where key like '%value%' ".                           +
     * +          +               +-------------+--------------------------------------------------------------+
     * +    s     +     string    + snl         + not like." where key not like '%value%' ".                   +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + se          + =." where key = 'value' ".                                   +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + sne         + !=." where key != 'value' ".                                 +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + sin         + in." where key in ('val1','val2') ".                         + 
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + snin         + not in." where key not in ('val1','val2') ".                + 
     * +----------+---------------+-------------+--------------------------------------------------------------+
     * +          +               + nisn        + is null.1:null;0:not null.                                   +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + nn          + null.                                                        +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + nnn         + not null.                                                    +
     * +          +               +-------------+--------------------------------------------------------------+
     * +    n     +     number    + ne          + =." where key = value ".                                     +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + nne         + !=." where key != value ".                                   +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + nb          + >." where key > value ".                                     +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + nbe         + >=." where key >= value ".                                   + 
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + ns          + <." where key < value ".                                     + 
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + nse         + <=." where key <= value ".                                   + 
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + nin         + in." where key in (val1,val2) ".                             + 
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + nnin        + not in." where key not in (val1,val2) ".                     + 
     * +----------+---------------+-------------+--------------------------------------------------------------+
     * +          +               + dnm         + <= .                                                         +
     * +          +               +-------------+--------------------------------------------------------------+
     * +    d     +    datetime   + dnl         + >= .                                                         +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + de          + = .                                                          +
     * +          +               +-------------+--------------------------------------------------------------+
     * +          +               + dne         + != .                                                         +
     * +----------+---------------+-------------+--------------------------------------------------------------+
     * </pre>
     */
    public static class Condition {
        private Map<String, Object> queryMap;
        private transient AtomicInteger sec = new AtomicInteger();

        public Condition() {
            this.queryMap = new HashMap<>();
        }

        /**
         * 直接设置条件
         * 
         * @param key
         * @param value
         * @return
         */
        public Condition addCondition(String key, Object value) {
            queryMap.put(key, value);
            return this;
        }

        /**
         * 自定义sql/hql语句拼接
         * 
         * @param sql
         * @return
         */
        public Condition addSql(String sql) {
            queryMap.put("_sql_" + sec.getAndIncrement(), sql);
            return this;
        }

        /**
         * <b>field</b> is null
         * 
         * @param field
         * @return
         */
        public Condition setStringIsNull(String field) {
            queryMap.put("_sisn_" + field, "0");
            return this;
        }

        /**
         * <b>field</b> is not null
         * 
         * @param field
         * @return
         */
        public Condition setStringIsNotNull(String field) {
            queryMap.put("_sisn_" + field, "1");
            return this;
        }

        /**
         * <b>field</b> like '%<b>value</b>%'
         * 
         * @param field
         * @param value
         */
        public Condition setStringLike(String field, String value) {
            queryMap.put("_sl_" + field, value);
            return this;
        }

        /**
         * <b>field</b> not like '%<b>value</b>%'
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setStringNotLike(String field, String value) {
            queryMap.put("_snl_" + field, value);
            return this;
        }

        /**
         * <b>field</b> = '<b>value</b>'
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setStringEqual(String field, String value) {
            queryMap.put("_se_" + field, value);
            return this;
        }

        /**
         * <b>field</b> != '<b>value</b>'
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setStringNotEqual(String field, String value) {
            queryMap.put("_sne_" + field, value);
            return this;
        }

        /**
         * <b>field</b> in ('<b>value1</b>','<b>value2</b>')
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setStringIn(String field, String... value) {
            queryMap.put("_sin_" + field, value);
            return this;
        }

        /**
         * <b>field</b> not in ('<b>value1</b>','<b>value2</b>')
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setStringNotIn(String field, String... value) {
            queryMap.put("_snin_" + field, value);
            return this;
        }

        /**
         * <b>field</b> is null
         * 
         * @param field
         * @return
         */
        public Condition setNumberIsNull(String field) {
            queryMap.put("_nisn_" + field, "0");
            return this;
        }

        /**
         * <b>field</b> is not null
         * 
         * @param field
         * @return
         */
        public Condition setNumberIsNotNull(String field) {
            queryMap.put("_nisn_" + field, "1");
            return this;
        }

        /**
         * <b>field</b> = <b>value</b>
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setNumberEqual(String field, String value) {
            queryMap.put("_ne_" + field, value);
            return this;
        }

        /**
         * <b>field</b> != <b>value</b>
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setNumberNotEqual(String field, String value) {
            queryMap.put("_nne_" + field, value);
            return this;
        }

        /**
         * <b>field</b> > <b>value</b>
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setNumberBig(String field, String value) {
            queryMap.put("_nb_" + field, value);
            return this;
        }

        /**
         * <b>field</b> < <b>value</b>
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setNumberSmall(String field, String value) {
            queryMap.put("_ns_" + field, value);
            return this;
        }

        /**
         * <b>field</b> >= <b>value</b>
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setNumberBigEqual(String field, String value) {
            queryMap.put("_nbe_" + field, value);
            return this;
        }

        /**
         * <b>field</b> <= <b>value</b>
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setNumberSmallEqual(String field, String value) {
            queryMap.put("_nse_" + field, value);
            return this;
        }

        /**
         * <b>field</b> in (<b>value1</b>,<b>value2</b>)
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setNumberIn(String field, String... value) {
            queryMap.put("_nin_" + field, value);
            return this;
        }

        /**
         * <b>field</b> not in (<b>value1</b>,<b>value2</b>)
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setNumberNotIn(String field, String... value) {
            queryMap.put("_nnin_" + field, value);
            return this;
        }

        /**
         * <b>field</b> >= '<b>value</b>'
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setDateBigEqual(String field, String value) {
            queryMap.put("_dnl_" + field, value);
            return this;
        }

        /**
         * <b>field</b> <= '<b>value</b>'
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setDateSmallEqual(String field, String value) {
            queryMap.put("_dnm_" + field, value);
            return this;
        }

        /**
         * <b>field</b> = '<b>value</b>'
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setDateEqual(String field, String value) {
            queryMap.put("_de_" + field, value);
            return this;
        }

        /**
         * <b>field</b> != '<b>value</b>'
         * 
         * @param field
         * @param value
         * @return
         */
        public Condition setDateNotEqual(String field, String value) {
            queryMap.put("_dne_" + field, value);
            return this;
        }

        /**
         * order by <b>field</b> asc
         * 
         * @param field
         * @return
         */
        public Condition setOrderByAsc(String field) {
            queryMap.put("_orderby_" + field, "asc");
            return this;
        }

        /**
         * order by <b>field</b> desc
         * 
         * @param field
         * @return
         */
        public Condition setOrderByDesc(String field) {
            queryMap.put("_orderby_" + field, "desc");
            return this;
        }

        /**
         * order by <b>field</b> <b>dir</b>
         * 
         * @param field
         * @param dir
         * @return
         */
        public Condition setOrderBy(String field, String dir) {
            if (field != null && !field.equals("")) {
                queryMap.put("_orderby_" + field, dir);
            }
            return this;
        }

        /**
         * 转换成{@link BaseService}需要的查询条件.
         * 
         * @return
         */
        public final Map<String, ?> toEntry() {
            return queryMap;
        }
    }
}
